package jmetal.util;

import Jama.Matrix;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;

public class ExtremumPoint {
	/**
	 * 获取solutionSet的ideal point
	 * @param solutionSet
	 * @return double[]
	 */
	public static double[] getIdealPoint(SolutionSet solutionSet) {		
		int objDim = solutionSet.get(0).getNumberOfObjectives();
		double[] idealPoint = new double[objDim];
		for(int i = 0;i<objDim;i++){
			double min = Double.MAX_VALUE;
			for(int j =0;j<solutionSet.size();j++){
				Solution solution = solutionSet.get(j);
				if(solution.getObjective(i)<min)
					min = solution.getObjective(i);
			}
			idealPoint[i] = min;
		}
		return idealPoint;
	}

	/**
	 * 获取solutionSet的nadir point
	 * 
	 * @param solutionSet
	 * @return double[]
	 */
	public static double[] getNadirPoint(SolutionSet solutionSet) {
		int objDim = solutionSet.get(0).getNumberOfObjectives();
		double[] nadirPoint = new double[objDim];
		for(int i = 0;i<objDim;i++){
			double max = Double.MIN_VALUE;
			for(int j =0;j<solutionSet.size();j++){
				Solution solution = solutionSet.get(j);
				if(solution.getObjective(i)>max)
					max = solution.getObjective(i);
			}
			nadirPoint[i] = max;
		}
		return nadirPoint;
	}
	
	/**
	 * 获取逼近的nadir point，用ASF函数
	 * @param solutionSet
	 * @return
	 */
	public static double[][] getRealNadirPoint(SolutionSet solutionSet,double[] zideal){
		int obj = solutionSet.get(0).getNumberOfObjectives();
		double[][] extremePoints = new double[obj][obj];

		for (int j = 0; j < obj; j++) {
			int index = -1;
			double min = Double.MAX_VALUE;

			for (int i = 0; i < solutionSet.size(); i++) {
				double asfValue = asfFunction(solutionSet.get(i), j, zideal);
				if (asfValue < min) {
					min = asfValue;
					index = i;
				}
			}

			for (int k = 0; k < obj; k++)
				extremePoints[j][k] = solutionSet.get(index).getObjective(k);
		}
		return extremePoints;

	}

	/**
	 * 获取解在aCornerPoint下的ASF值
	 * @param aCornerPoint
	 * @param solution
	 * @return
	 */
	private static double asfFunction(Solution sol, int j,double[] zideal) {
		int obj = sol.getNumberOfObjectives();
		double max = Double.MIN_VALUE;
		double epsilon = 1.0E-6;

		for (int i = 0; i < obj; i++) {

			double val = Math.abs(sol.getObjective(i) - zideal[i]);

			if (j != i)
				val = val / epsilon;

			if (val > max)
				max = val;
		}

		return max;
	}

	public static double[] getInterceptPoint(SolutionSet solutionSet) {
		int obj = solutionSet.get(0).getNumberOfObjectives();
		double[] intercepts = new double[obj];

		double[][] temp = new double[obj][obj];
		double[] zideal = SingletonExtremePoint.getIdealPointInstance(solutionSet);
		double[][] extremePoints = getRealNadirPoint(solutionSet,zideal);
		
		double[] zmax = getNadirPoint(solutionSet);
		for (int i = 0; i < obj; i++) {
			for (int j = 0; j < obj; j++) {
				double val = extremePoints[i][j] - zideal[j];
				temp[i][j] = val;
			}
		}

		Matrix EX = new Matrix(temp);

		if (EX.rank() == EX.getRowDimension()) {
			double[] u = new double[obj];
			for (int j = 0; j < obj; j++)
				u[j] = 1;

			Matrix UM = new Matrix(u, obj);

			Matrix AL = EX.inverse().times(UM);

			int j = 0;
			for (j = 0; j < obj; j++) {

				double aj = 1.0 / AL.get(j, 0) + zideal[j];

				if ((aj > zideal[j]) && (!Double.isInfinite(aj)) && (!Double.isNaN(aj)))
					intercepts[j] = aj;
				else
					break;
			}
			if (j != obj) {
				for (int k = 0; k < obj; k++)
					intercepts[k] = zmax[k];
			}

		} else {
			for (int k = 0; k < obj; k++)
				intercepts[k] = zmax[k];
		}
		
		return intercepts;
	}
}
